var smile_face = "data:img/gif;base64,R0lGODlhFQAVAJEAAAAAAP//AL29vQAAACH5BAAHAP8ALAAAAAAVABUAAAJAlI+py50AoUMwWCsduBy33XXAAoaiUlZY+nBq8MKUSY9HSbtzft4X/vu1MCLhcBXRoXgyBlD5AWYmgsiUis0yCgA7";
var good_face = "data:img/gif;base64,R0lGODlhFQAVAJEAAAAAAP//AMDAwICAACH5BAAHAP8ALAAAAAAVABUAAAJHlI+py50AoUMwWCsduBy33XXAAoaiAkZqFYwUprZx+27xTR/swMoD/DKZXIaSkEMsXoytJQo58zyPOdIxSWJmJoIV9wueFAAAOw==";
var bad_face = "data:img/gif;base64,R0lGODlhFQAVAJEAAAAAAP//AMDAwAAAACH5BAAHAP8ALAAAAAAVABUAAAJDlI+py50AoUMwWCsduBy33XXAAm5gYHrPdWLs6p6parShSN36eNg6LbBFKhxejyV6wXwo4PGH+vyMDCKLqhlOttxuAQA7";
var blank_tile = new Image();
var flag_tile = new Image();
var bomb_tile = new Image();
var mine_tile = new Image();
blank_tile.src = "data:img/gif;base64,R0lGODlhGQAZAJEAAP///8DAwICAgAAAACH5BAQUAP8ALAAAAAAZABkAAAJKhI+pFrH/GpwnCFGb3nxfzHQi92XjWYbnmAIrepkvGauzV7s3Deq71vrhekJgrtgIIpVFptD5g+6kN+osZflot9xPsgvufsPkSwEAOw==";
flag_tile.src = "data:img/gif;base64,R0lGODlhGQAZAKIAAP///8DAwICAgP8AAAAAAAAAAAAAAAAAACH5BAAHAP8ALAAAAAAZABkAAANsCLrcriG8OSO9KwiRo//gt3FQaIJjZw7DmZYh25ovEMtzWH+47G6qno8GhAWEOVTRBur9SMxbUrQ8BQiEpyqE1RpBXSLUGtZVI9i0Wu3ZodfwbMR9ja/bZ6s3qjeTNCOBgoMjc4SHhIaIixsJADs=";
bomb_tile.src = "data:img/gif;base64,R0lGODlhGQAZAJEAAP///4CAgP8AAAAAACH5BAQUAP8ALAAAAAAZABkAAAJgjI+py70Co5wUmhrHwPFyzVlBCIYeBGqqik6nkK4s7I6TjFOvCvR42bGhND3AbyPZEX2/GuwILV2iUZGEOgtesUhthuu8VcNbqE74fOZoSTQFiHm9u3G3OCSQ4yv6/aQAADs=";
mine_tile.src = "data:img/gif;base64,R0lGODlhGQAZAJEAAP///76+voKCggAAACH5BAAHAP8ALAAAAAAZABkAAAJglI+py70Bo5wUmhrHwPFyzVlCCIYeBGqqik5nkK4s7I6TjFOvCvR42bGhND3AbyPZEX2/GuwILV2iUZGEOgtesUhthuu8VcNbqE74fOZoSTQFiHm9u3G3OBSQ4yv6/aQAADs=";
var digit = []; for (let i = 0; i < 10; i++) { digit[i] = new Image(); }
digit[0].src = "data:img/gif;base64,R0lGODlhDQAXAJEAAP8AAIAAAAAAAAAAACH5BAQUAP8ALAAAAAANABcAAAI5lI8Jy3wgmoMRymoc0vqt/G1hB1JkZVKKaQSC60YI/NZPW8dpApZrqvKhfkIPkIi5jFANWUkS5CUKADs=";
digit[1].src = "data:img/gif;base64,R0lGODlhDQAXAJEAAP8AAIAAAAAAAAAAACH5BAQUAP8ALAAAAAANABcAAAI3lI8psc33mDQAmilAdUnv1mkXeHhWuGGlOCpsxGXIpII0dYbjs358v0PlgDGiDfQKPj6cmkJRAAA7";
digit[2].src = "data:img/gif;base64,R0lGODlhDQAXAJEAAP8AAIAAAAAAAAAAACH5BAQUAP8ALAAAAAANABcAAAI8lI8Jy3whmgMvNmsgRC4nSwmaslRkOHKl962QVIYgfFAwta3JBu6i0UHwgp6cztQT/jCSZWTmGN5kn08BADs=";
digit[3].src = "data:img/gif;base64,R0lGODlhDQAXAJEAAP8AAIAAAAAAAAAAACH5BAQUAP8ALAAAAAANABcAAAI5lI8Jy3whmgMvNmsgRC4nSwmaslRkOHKl962QVIYgXMGUvJFebnRi6/qpcECU8OB7XYK2CNIm+3wKADs=";
digit[4].src = "data:img/gif;base64,R0lGODlhDQAXAJEAAP8AAIAAAAAAAAAAACH5BAQUAP8ALAAAAAANABcAAAI8lI8psc0HDJsmCmDptdhCXIFIF3rlOYpkyplftXWgJ9cHU8+3skkNu0usNB/PA+gQin4a0YPyMEF/PF4BADs=";
digit[5].src = "data:img/gif;base64,R0lGODlhDQAXAJEAAP8AAIAAAAAAAAAAACH5BAQUAP8ALAAAAAANABcAAAI5lI8Jy3wgmgtmxSZotYhql2gX1GUbWZ6heSWGCEkWLHNmHR0iwnmKvVOZgiAWr2cU3jBIHKpmc7kKADs=";
digit[6].src = "data:img/gif;base64,R0lGODlhDQAXAJEAAP8AAIAAAAAAAAAAACH5BAQUAP8ALAAAAAANABcAAAI5lI8Jy3wgmgtmxSZotYhql2gX1GUbWZ6heSWGCEkWLHPRiJE2woFPvxupeEDU0HeM5XQ4B6oWdCEKADs=";
digit[7].src = "data:img/gif;base64,R0lGODlhDQAXAJEAAP8AAIAAAAAAAAAAACH5BAQUAP8ALAAAAAANABcAAAI5lI8Jy3whmgMvNmsgRC4nSwmaslRkOHKl963buIUejLziHZnkfOpHl/qtcCoU0dDBpVy8WO0W/EgLADs=";
digit[8].src = "data:img/gif;base64,R0lGODlhDQAXAIAAAP8AAAAAACH5BAQUAP8ALAAAAAANABcAAAI0jI8Jy3wQmoMRymoc0vqt/G1hB1JkZVKKiTaRJ4VvbIGJja6pWvbirvPBbJdRawKL3ZaGAgA7";
digit[9].src = "data:img/gif;base64,R0lGODlhDQAXAJEAAP8AAIAAAAAAAAAAACH5BAQUAP8ALAAAAAANABcAAAI6lI8Jy3wgmoMRymoc0vqt/G1hB1JkZVKKiTaRJ4VC0E4HnWDzLqp4b6D9SrecRrjy1XS0mAUWy0kNBQA7";
var tile = []; for (let i = 0; i < 9; i++) { tile[i] = new Image(); }
tile[0].src = "data:img/gif;base64,R0lGODlhGQAZAKIAAM7OzsbGxr6+vra2trKysqampoKCggAAACH5BAAHAP8ALAAAAAAZABkAAANHaLrc3mWQSau9xAwQuv9gGBhEIJxoqq4CabLw6sY0Otf0jcP6Lpc+HjD4exFTvWNrqDwlj09iNDj1VXdXXLa2zTGb3VgYlgAAOw==";
tile[1].src = "data:img/gif;base64,R0lGODlhGQAZAJEAAMDAwICAgAAA/wAAACH5BAQUAP8ALAAAAAAZABkAAAJMjI+py70Ao5wUmorxzTxuLIRC9lFiSAbZOWqqybZVCcWoC8fpeu5gj/uJfBUWMXebvYpAJdJGoQFsTc8yQh1OpJ3otesEH8XbLzlSAAA7";
tile[2].src = "data:img/gif;base64,R0lGODlhGQAZALMAAMDAwKu5q6i4qKW3pZy0nJaylpCwkIquioCAgACAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAHAP8ALAAAAAAZABkAAAReEMlJq704X8C7/yAnhSQ5lmh3cknrvi64wvT7zXV9I50N+ipeihXzrFACoEhYMtB2pSSsIGN6CrRBIHQEEGjb0pEmGOJch+Gyl3samW13kB0vztViKx665+r7a4AfEQA7";
tile[3].src = "data:img/gif;base64,R0lGODlhGQAZAJEAAMDAwICAgP8AAAAAACH5BAQUAP8ALAAAAAAZABkAAAJOjI+py70Ao5wUmorxzTxuIITiOFIfiZbSmabT16le0EWyRdeg+OZTGzL5JECBsFI86m4AGIfpzEB9RVLPVuWtqFnjVZeJgmdjzbBMRk8KADs=";
tile[4].src = "data:img/gif;base64,R0lGODlhGQAZAJEAAMDAwICAgAAAmQAAgCH5BAAHAP8ALAAAAAAZABkAAAJdjI+py70Ao5wUmorxzTzuOgjAQJLUN5FiaU5oVK7sGVAxxA50Gor47KrBVJLc7hfilY6jnHMp+TynwYjgisXmfB4hx1jtgKPezLjbaULJ6bOlnK684mG6HG5H5ykFADs=";
tile[5].src = "data:img/gif;base64,R0lGODlhGQAZAJEAAMDAwICAgIAAAAAAACH5BAQUAP8ALAAAAAAZABkAAAJOjI+py70Ao5wUmorxzTxuIITiSE4fiY5mEKXu2oodDKmzx9bybeWgW6L9gDZcjLgz3oo9HhPw6TxPyGRTVxUIs1ohjxL9SsLia3nsO0MKADs=";
tile[6].src = "data:img/gif;base64,R0lGODlhGQAZAJEAAMDAwICAgACAgAAAACH5BAQUAP8ALAAAAAAZABkAAAJTjI+py70Ao5wUmorxzTxuKITiKFIfiZbTmaJmEI3dCoPqbNWAjOdxS3r9gDyPjhiUsEKVos/GpDgBS0Hz9twhsdTjNmqUfIU9ja5MQ1c+6nBbUgAAOw==";
tile[7].src = "data:img/gif;base64,R0lGODlhGQAZAJEAAL6+voKCggAAAAAAACH5BAAHAP8ALAAAAAAZABkAAAJMjI+py70Ao5wUmorxzTxuIITiSE4fiY5mEKXu2rUiHIOz9HElznY771NRcpQfrWI8TpJK2S1DtD2hPWeoRhTGojVgV1P9NsWWMBlSAAA7";
tile[8].src = "data:img/gif;base64,R0lGODlhGQAZAIAAAMDAwICAgCH5BAQUAP8ALAAAAAAZABkAAAJKjI+py70Ao5wUmorxzTxu63xeMIYi8JnHlK4UwpLgOctjaUuwnqtvb/rxQsJaZXcz/k4tGsqVfPp4OCK1yih2OM7t1avJgWNjTAEAOw==";
function $(a) {
  return document.getElementById(a);
}
var Row, Col, XY, M, RM, RB, SW, SH;
var can; // 雷区对应的canvas
var ctx; // can的2d context
const [MINE, BLANK, OPENED, FLAG, LEN] = [-1, 0, 1, 2, 25];
function toPoint(idx) {
  return [idx % Col, Math.floor(idx / Col)];
}
function toIndex(x, y) {
  return x + y * Col;
}
function around(idx, f) {
  const border = [[-1, -1], [0, -1], [1, -1], [-1, 0], [1, 0], [-1, 1], [0, 1], [1, 1]];
  let [x, y] = toPoint(idx);
  for ([x1, y1] of border.map(e =>
    [e[0] + x, e[1] + y]).filter(e =>
      e[1] >= 0 && e[1] < Row && e[0] >= 0 && e[0] < Col)) {
    f(toIndex(x1, y1));
  }
}
function drawTile(img, idx) {
  let [x, y] = toPoint(idx);
  ctx.drawImage(img, x * LEN, y * LEN);
}
function start() {
  document.oncontextmenu = function () {
    return false;
  }
  document.onselectstart = function () {
    return false;
  }
  can = $("paf");
  ctx = can.getContext("2d");
  can.onmousedown = function (e) {
    mouseDown(e);
  };
  initMode(1);
}
function initMode(m) {
  SW = document.body.clientWidth;
  SH = document.body.clientHeight;
  if (m == null) {
    m = SW < 560 ? 1 : 2;
  }
  $("custom").style.display = (m == 4 ? "" : "none");
  if (m == 1) {
    [Row, Col, M, XY] = [9, 9, 10, 81];
  } else if (m == 2) {
    [Row, Col, M, XY] = [16, 16, 40, 256];
  } else if (m == 3) {
    [Row, Col, M, XY] = [30, 16, 99, 480];
    if (SW > SH) {
      [Row, Col] = [16, 30];
    }
  } else if (m == 4) {
    Col = parseInt($("hm").value);
    Row = parseInt($("wm").value);
    XY = Row * Col;
    M = parseInt($("mm").value);
    if (M > XY*0.21) {
      M = Math.floor(XY*0.21);
    }
  } else {
    return;
  }
  after_initMode_();
  initGame();
}
var wrong_mine = [];
var h_wrong = 0;
var tilemap = [];
function initGame() {
  //初始化定时器
  clearInterval(h_time);
  h_time = 0;
  clearInterval(h_wrong);
  h_wrong = 0;
  // 初始化变量
  wrong_mine = [];
  use_time = 0;
  tilemap.length = XY;
  for (let i = 0; i < XY; ++i) {
	tilemap[i] = { outer: BLANK, inner: 0 };
  }
  RM = M;
  RB = XY - M;
  q_click = [];
  q_0 = [];
  q_posi = [];
  // 初始化界面
  let n = Col * LEN;
  $("p42").style.width = n + 4 + "px";
  can.width = n;
  can.height = Row * LEN;
  $("face").src = smile_face;
  tilemap.forEach((ele, idx) => drawTile(blank_tile, idx));
  showNum("rm", RM);
  showNum("es", 0);

  after_initGame_();
}
function mouseDown(e) {
  let f = can.getBoundingClientRect();
  let x = Math.floor((e.clientX - f.left) / LEN);
  let y = Math.floor((e.clientY - f.top) / LEN);
  if (h_time < 0 || y < 0 || y >= Row || x < 0 || x >= Col)
    return;
  let idx = toIndex(x, y);
  if (e.button === 2) { // 右键
    Mark(idx);
  } else if (e.button === 1) { // 中键
    helpOpen(idx);
  } else if (e.button === 0) { // 左键
    if (tilemap[idx].outer === BLANK) {
      Open(idx);
    } else if (tilemap[idx].outer === OPENED && tilemap[idx].inner > 0) {
      multiOpen(idx);
    }
  }
}
function Mark(idx) {
  let t = tilemap[idx];
  if (t.outer === BLANK) {
    if (RM > 0) {
      _Mark(idx);
      showNum("rm", RM);
      autoOpen_after_Mark_(idx);
    }
  } else if (t.outer === FLAG) {
    drawTile(blank_tile, idx);
    t.outer = BLANK;
    showNum("rm", ++RM);
  }
}
function _Mark(idx) {
  drawTile(flag_tile, idx);
  --RM;
  tilemap[idx].outer = FLAG;
}
var q_click = [];
var q_0 = [];
var q_posi = [];
function Open(idx) {
  if (RB + RM == XY) { // 开局第一点，也可以用h_time === 0
    firstClick(idx);
  }
  q_click.push(idx);
  for (let i = 0; i < q_click.length; ++i) {
    idx = q_click[i];
    let t = tilemap[idx];
    if (t.outer === BLANK) {
      if (t.inner === MINE) {
        fail(idx);
        return;
      }
      _Open(idx);
      if (t.inner === 0) {
        q_0.push(idx);
      } else {
        q_posi.push(idx);
      }
      for (let j = 0; j < q_0.length; ++j) {
        around(q_0[j], idx1 => {
          if (tilemap[idx1].outer === BLANK) {
            _Open(idx1);
            if (tilemap[idx1].inner === 0) {
              q_0.push(idx1);
            } else {
              q_posi.push(idx1);
            }
          }
        });
      }
      if (RB == 0) {
        success();
        return;
      }
      q_0 = [];
      autoFlag_after_click_();
      autoOpen_after_click_();
      update_chance_();
    }
  }
  q_click = [];
}
function firstClick(idx) {
  h_time = setInterval(function () {
    showNum("es", ++use_time);
  }, 1000);
  let arr = [];
  let m = new Map();
  let limit = XY - 1;
  m.set(idx, limit--);
  around(idx, idx1 => m.set(idx1, limit--));
  for (let i = 0; i < M; i++, limit--) {// 随机取样
    let n = Math.floor(Math.random() * limit);
    arr[i] = m.get(n) ?? n;
    m.set(n, m.get(limit) ?? limit);
  }
  arr.forEach(ele => around(ele, idx1 => tilemap[idx1].inner++));// 初始化周围雷数
  arr.forEach(ele => tilemap[ele].inner = MINE); // 布雷
}
function _Open(idx) {
  drawTile(tile[tilemap[idx].inner], idx);
  RB--;
  tilemap[idx].outer = OPENED;
}
function multiOpen(idx) {
  if (tilemap[idx].outer !== OPENED)
    return;
  around(idx, idx1 => {
    if (tilemap[idx1].outer === BLANK) {
      q_click.push(idx1);
    }
  });
  let { flag } = count(idx);
  if (tilemap[idx].inner === flag) {
    if (q_click.length > 0) {
      let pos = q_click[0];
      q_click.shift();
      Open(pos);
    }
  } else {
    Blink();
  }
}
function showNum(id, num) {
  let cav = $(id);
  let ctx = cav.getContext("2d");
  let len = 3;
  if (num < 10) {
    num = "00" + num;
  } else if (num < 100) {
    num = "0" + num;
  } else {
    num = num.toString();
  }
  let n = num.length;
  if (n != len) {
    cav.width = n * 13;
    len = n;
  }
  for (let i = 0; i < n; i++) {
    ctx.drawImage(digit[parseInt(num.charAt(i))], i * 13, 0);
  }
}
function Blink() {
  for (let idx of q_click) {
    drawTile(tile[0], idx);
    setTimeout((function (idx1) {
      return function () {
        drawTile(blank_tile, idx1);
      }
    })(idx), 120);
  }
  q_click = [];
}
function fail(idx) {
  tilemap[idx].outer = OPENED;
  drawTile(bomb_tile, idx);
  clearInterval(h_time);
  h_time = -1;
  $("face").src = bad_face;
  tilemap.forEach((ele, idx1) => {
    if (ele.outer === BLANK && ele.inner === MINE) {
      drawTile(mine_tile, idx1);
    } else if (ele.outer === FLAG && ele.inner !== MINE) {
      wrong_mine.push(idx1);
    }
  });
  if (wrong_mine.length > 0) {
    h_wrong = setInterval(function () {
      var W = true;
      return function () {
        for (let pos of wrong_mine) {
          drawTile(W === true ? tile[tilemap[pos].inner] : flag_tile, pos);
        }
        W = !W;
      }
    }(), 800);
  }
}
function success() {
  clearInterval(h_time);
  h_time = -1;
  $("face").src = good_face;
  tilemap.forEach((ele, idx) => {
    if (ele.outer === BLANK && ele.inner === MINE) {
      _Mark(idx);
    }
  });
  showNum("rm", M);
}
var h_time = 0; // -1结束，0未开始，>0进行中
var use_time;
function count(idx) {
  let n = { blank: 0, flag: 0 };
  around(idx, idx1 => {
    if (tilemap[idx1].outer === BLANK) {
      n.blank++;
    }
    if (tilemap[idx1].outer === FLAG) {
      n.flag++;
    }
  });
  return n;
}
function userDef() {
  initMode(4);
}

function after_initMode_() {
  coe = Math.floor(XY / M * 19.5);
}
function after_initGame_() {
  auto_flag = $("af").checked;
  auto_open = $("ao").checked;
  chance = 0;
  use_chance = 0;
  $("lab").innerHTML = "还有0次机会";
}
/// 自动标记 ///
var auto_flag = false;
function setAutoFlag() {
  auto_flag = $("af").checked;
}
function autoFlag_after_click_() {
  if (auto_flag) {
    for (let j = 0; j < q_posi.length;) {
      let idx0 = q_posi[j];
      let { blank, flag } = count(idx0);
      if (blank + flag === tilemap[idx0].inner) {
        if (blank > 0) {
          around(idx0, idx1 => {
            if (tilemap[idx1].outer === BLANK) {
              _Mark(idx1);// 消除间接递归
            }
          });
        }
        q_posi.splice(j, 1);
      } else {
        j++;
      }
    }
    showNum("rm", RM);
  }
}
/// 自动点开 ///
var auto_open = false;
function setAutoOpen() {
  auto_open = $("ao").checked;
}
function autoOpen_after_click_() {
  if (auto_open) {
    for (let j = 0; j < q_posi.length;) {
      let idx0 = q_posi[j];
      let { blank, flag } = count(idx0);
      if (flag === tilemap[idx0].inner) {
        if (blank > 0) {
          around(idx0, idx1 => {
            if (tilemap[idx1].outer === BLANK) {
              q_click.push(idx1);// 消除间接递归
            }
          });
        }
        q_posi.splice(j, 1);
      } else {
        j++;
      }
    }
  }
}
function autoOpen_after_Mark_(idx) {
  if (auto_open) {
    around(idx, idx1 => {
      if (h_time > 0 && tilemap[idx1].outer === OPENED && tilemap[idx1].inner > 0) {
        let { blank, flag } = count(idx1);
        if (blank > 0 && flag === tilemap[idx1].inner) {
          multiOpen(idx1);
        }
      }
    });
  }
}
/// 辅助点开 ///
var chance;
var use_chance;
var coe;
function helpOpen(idx) {
  if (chance <= use_chance || h_time < 0)
    return;
  let n = use_time % 5;
  let arr = [];
  tilemap.forEach((ele, idx1) => {
    if (ele.outer === BLANK && ele.inner === n) {
      arr.push(idx1);
    }
  });
  use_chance++;
  if (arr.length > 0) {
    let [x, y] = toPoint(idx);
    let pos = arr.reduce((a, b) => {
      let [x1, y1] = toPoint(a);
      let [x2, y2] = toPoint(b);
      disa = Math.hypot(x1 - x, y1 - y);
      disb = Math.hypot(x2 - x, y2 - y);
      return disa < disb ? a : b;
    });
    Open(pos);
  } else {
    update_chance_();
  }
}
function update_chance_() {
  chance = Math.floor((XY - M - RB) / coe);
  $("lab").innerHTML = `还有${chance - use_chance}次机会`;
}
